package me.itsoo.artemis.framework.core;

import me.itsoo.artemis.framework.core.util.StringUtils;

import java.util.LinkedHashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;

/**
 * ResourceScanner
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/24
 */
public class ResourceScanner {

    private final Set<Class<?>> allScannedTypes;

    private final String basePackage;

    public ResourceScanner(String basePackage) {
        this.basePackage = basePackage;
        this.allScannedTypes = new LinkedHashSet<>(16);

        init();
    }

    public ResourceScanner(Class<?> scannedClass) {
        this.basePackage = getPackageName(scannedClass);
        this.allScannedTypes = new LinkedHashSet<>(16);

        init();
    }

    private void init() {
        final FolderClassResource resource = new FolderClassResource(basePackage);

        for (String className : resource.getFilenames()) {
            try {
                final Class<?> tarType = Class.forName(className);
                allScannedTypes.add(tarType);
            } catch (ClassNotFoundException ignore) { // NOSONAR
            }
        }
    }

    /**
     * 获取 Class 集合
     *
     * @return Set
     */
    public Class<?>[] getClasses() {
        return allScannedTypes.toArray(new Class[0]);
    }

    /**
     * 获取 Class 集合
     *
     * @param predicate 给定条件
     * @return Set
     */
    public Class<?>[] getClasses(Predicate<Class<?>> predicate) {
        final Set<Class<?>> set = new LinkedHashSet<>();
        for (Class<?> type : allScannedTypes) {
            if (predicate.test(type)) {
                set.add(type);
            }
        }

        return set.toArray(new Class[0]);
    }

    /**
     * 获取扫描类的包名
     *
     * @param scannedClass Class
     * @return String
     */
    private String getPackageName(Class<?> scannedClass) {
        String className = Optional.ofNullable(scannedClass).map(Class::getCanonicalName).orElse("");
        if (StringUtils.isBlank(className)) {
            return null;
        }

        while (className.charAt(0) == '[') {
            className = className.substring(1);
        }

        if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
            className = className.substring(1);
        }

        final int i = className.lastIndexOf(".");
        return (i == -1) ? className : className.substring(0, i);
    }
}
